/*

 SD - a slightly more friendly wrapper for sdfatlib

 This library aims to expose a subset of SD card functionality
 in the form of a higher level "wrapper" object.

 License: GNU General Public License V3
          (Because sdfatlib is licensed with this.)

 (C) Copyright 2010 SparkFun Electronics

 */

#ifndef __SD_H__
#define __SD_H__

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include <SPI.h>
#include <utility/SdFat.h>
#include <utility/SdFatUtil.h>
#include <utility/Sd2Card.h>

#define FILE_READ F_READ
#define FILE_WRITE (F_READ | F_WRITE | F_CREAT)

namespace ext{
  class File : public Stream {
   private:
    char _name[13]; // our name
    SdFile *_file;  // underlying file pointer

  public:
    File(SdFile f, const char *name);     // wraps an underlying SdFile
    File(void);      // 'empty' constructor
    ~File(void);     // destructor
  #if ARDUINO >= 100
    virtual size_t write(uint8_t);
    virtual size_t write(const uint8_t *buf, size_t size);
  #else
    virtual void write(uint8_t);
    virtual void write(const uint8_t *buf, size_t size);
  #endif
    virtual int read();
    virtual int peek();
    virtual int available();
    virtual void flush();
    int read(void *buf, uint16_t nbyte);
    boolean seek(uint32_t pos);
    uint32_t position();
    uint32_t size();
    void close();
    operator bool();
    char * name();

    boolean isDirectory(void);
    File openNextFile(uint8_t mode = F_RDONLY);
    void rewindDirectory(void);
    
    using Print::write;
  };
}

class SDClass {

private:
  // These are required for initialisation and use of sdfatlib
  Sd2Card card;
  SdVolume volume;
  SdFile root;
  
  // my quick&dirty iterator, should be replaced
  SdFile getParentDir(const char *filepath, int *indx);
public:
  // This needs to be called to set up the connection to the SD card
  // before other methods are used.
  boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN, int8_t mosi = -1, int8_t miso = -1, int8_t sck = -1);
  
  //call this when a card is removed. It will allow you to inster and initialise a new card.
  void end(); 
  
  // Open the specified file/directory with the supplied mode (e.g. read or
  // write, etc). Returns a File object for interacting with the file.
  // Note that currently only one file can be open at a time.
  ext::File open(const char *filename, uint8_t mode = FILE_READ);

  // Methods to determine if the requested file path exists.
  boolean exists(char *filepath);

  // Create the requested directory heirarchy--if intermediate directories
  // do not exist they will be created.
  boolean mkdir(char *filepath);
  
  // Delete the file.
  boolean remove(char *filepath);
  
  boolean rmdir(char *filepath);
  
  void enableCRC(boolean mode);

private:

  // This is used to determine the mode used to open a file
  // it's here because it's the easiest place to pass the 
  // information through the directory walking function. But
  // it's probably not the best place for it.
  // It shouldn't be set directly--it is set via the parameters to `open`.
  int fileOpenMode;
  
  friend class File;
  friend boolean callback_openPath(SdFile&, char *, boolean, void *); 
};

extern SDClass SD;

#endif
